// This file is part of the 'texasholdem' project, an open source
// Texas Hold'em poker application written in Java.
//
// Copyright 2009 Oscar Stigter
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.TexasHoldem.core;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.TexasHoldem.core.actions.*;;

/**
 * A Texas Hold'em player. <br />
 * <br />
 * 
 * The player's actions are delegated to a {@link Client}, which can be either
 * human-controlled or AI-controlled (bot).
 * 
 * @author Oscar Stigter
 */
public class Player {

    /** Name. */
    private final String name;

    /** Client application responsible for the actual behavior. */
    private final Client client;

    /** Hand of cards. */
    private final Hand hand;

    /** Current amount of cash. */
    private int cash;
    
	/** Whether the player has hole cards. */
    private boolean hasCards;

    /** Current bet. */
    private int bet;

    /** Last action performed. */
    private Action action;
    
    private List<Action> actionhis = new ArrayList<Action>();
    
    private List<Action> preFlop = new ArrayList<Action>();
    
    private List<Action> Flop = new ArrayList<Action>();
    
    private List<Action> trun = new ArrayList<Action>();
    
    private List<Action> river = new ArrayList<Action>();

    
    public List<Action> getActionhis()
	{
		return actionhis;
	}


	private StringBuilder sum = new StringBuilder();
    
    public  HandValue curhandValue = null;
    
    public int pos = -1;
    
    
	public int getPos() {
		return pos;
	}

	public void setPos(int pos) {
		this.pos = pos;
	}

	public HandValue getCurhandValue() {
		return curhandValue;
	}

	public void setCurhandValue(HandValue curhandValue) {
		this.curhandValue = curhandValue;
	}

	/**
     * Constructor.
     * 
     * @param name
     *            The player's name.
     * @param cash
     *            The player's starting amount of cash.
     * @param client
     *            The client application.
     */
    public Player(String name, int cash, Client client) {
        this.name = name;
        this.cash = cash;
        this.client = client;

        hand = new Hand();

        resetHand();
    }

    /**
     * Returns the client.
     * 
     * @return The client.
     */
    public Client getClient() {
        return client;
    }

    /**
     * Prepares the player for another hand.
     */
    public void resetHand() {
        hasCards = false;
        hand.removeAllCards();
        resetBet(0);
        this.actionhis.clear();
        this.preFlop.clear();
        this.Flop.clear();
        this.trun.clear();
        this.river.clear();
    }

    /**
     * Resets the player's bet.
     */
    public void resetBet(int boardsize) {
        bet = 0;
        action = (hasCards() && cash == 0) ? Action.ALL_IN : null;
        if(boardsize == 0)
        {
        	this.preFlop.addAll(this.actionhis);
        }
        if(boardsize == 3)
        {
        	this.Flop.addAll(this.actionhis);
        }
        if(boardsize == 4)
        {
        	this.trun.addAll(this.actionhis);
        }
        if(boardsize == 5)
        {
        	this.river.addAll(this.actionhis);
        }
        this.actionhis.clear();
    }

    /**
     * Sets the hole cards.
     */
    public void setCards(List<Card> cards) {
        hand.removeAllCards();
        if (cards != null) {
            if (cards.size() == 2) {
                hand.addCards(cards);
                hasCards = true;
            } else {
                throw new IllegalArgumentException("Invalid number of cards");
            }
        }
    }

    /**
     * Returns whether the player has his hole cards dealt.
     * 
     * @return True if the hole cards are dealt, otherwise false.
     */
    public boolean hasCards() {
        return hasCards;
    }

    /**
     * Returns the player's name.
     * 
     * @return The name.
     */
    public String getName() {
        return name;
    }

    public void setCash(int cash) {
		this.cash = cash;
	}
    
    /**
     * Returns the player's current amount of cash.
     * 
     * @return The amount of cash.
     */
    public int getCash() {
        return cash;
    }

    /**
     * Returns the player's current bet.
     * 
     * @return The current bet.
     */
    public int getBet() {
        return bet;
    }
    
    /**
     * Sets the player's current bet.
     * 
     * @param bet
     *            The current bet.
     */
    public void setBet(int bet) {
        this.bet = bet;
    }

    /**
     * Returns the player's most recent action.
     * 
     * @return The action.
     */
    public Action getAction() {
        return action;
    }
    
    /**
     * Sets the player's most recent action.
     * 
     * @param action
     *            The action.
     */
    public void setAction(Action action) {
        this.action = action;
        if(action != null)
        	this.actionhis.add(action);
    }

    /**
     * Indicates whether this player is all-in.
     * 
     * @return True if all-in, otherwise false.
     */
    public boolean isAllIn() {
        return hasCards() && (cash == 0);
    }

    /**
     * Returns the player's hole cards.
     * 
     * @return The hole cards.
     */
    public Card[] getCards() {
        return hand.getCards();
    }
    public String getCardsStr()
    {
    	return hand.toString();
    }
    /**
     * Posts the small blind.
     * 
     * @param blind
     *            The small blind.
     */
    public void postSmallBlind(int blind) {
        action = Action.SMALL_BLIND;
        cash -= blind;
        bet += blind;
        action.setAmount(blind);
        this.actionhis.add(Action.SMALL_BLIND);
    }

    /**
     * Posts the big blinds.
     * 
     * @param blind
     *            The big blind.
     */
    public void postBigBlind(int blind) {
        action = Action.BIG_BLIND;
        cash -= blind;
        bet += blind;
        action.setAmount(blind);
        this.actionhis.add(Action.BIG_BLIND);
    }
    
    /**
     * Pays an amount of cash.
     * 
     * @param amount
     *            The amount of cash to pay.
     */
    public void payCash(int amount) {
        if (cash >= amount) 
        	cash -= amount;
        else
        {
        	System.out.print("pay:" + this.name + ",cash:" + this.cash + "amount" + amount);
        	throw new IllegalStateException("Player asked to pay more cash than he owns!");
        }
        
    }
    
    /**
     * Wins an amount of money.
     * 
     * @param amount
     *            The amount won.
     */
    public void win(int amount) {
        cash += amount;
    }

    /**
     * Returns a clone of this player with only public information.
     * 
     * @return The cloned player.
     */
    public Player publicClone() {
        Player clone = new Player(name, cash, null);
        clone.bet = bet;
        clone.actionhis.addAll(this.actionhis);
        return clone;
    }

    /** {@inheritDoc} */
    @Override
    public String toString() {
        return name;
    }
    
    
    public String GetSummary(Map<Player, Integer> potDivision )
    {
    	StringBuilder sum = new StringBuilder();
    	
    	if(potDivision.keySet().contains(this))
		{
			 for (Player winner : potDivision.keySet()) 
			 {
				 if(winner.equals(this))
				 {
					 int potShare = potDivision.get(winner);
					 if(this.curhandValue != null)
						 sum.append(String.format("won (%d) with %s",potShare,this.curhandValue.getDescription()));
					 else
						 sum.append(String.format("won (%d)",potShare));
				 }
				 
			 }
			
		}
		else
		{
			if(this.preFlop.contains(Action.FOLD) && this.preFlop.size() > 1)
				sum.append("folded before preFlop");
			else if(this.preFlop.contains(Action.FOLD) && this.preFlop.size() == 1)
				sum.append("folded before preFlop (didn't bet");
			else if(this.curhandValue != null)
				sum.append(String.format("lost with %s",this.curhandValue.getDescription()));
			else
				sum.append(String.format("lost"));
		}
    	
    	return sum.toString();
    }
}
